/*
 * @Author: wuqingchun
 * @Date: 2024-03-08 17:07:50
 * @Description: 
 * @LastEditors: wuqingchun
 * @LastEditTime: 2024-03-30 15:17:45
 */
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <errno.h>

#include <unistd.h>
#include <sys/mman.h>
#include <pthread.h>

#include <unordered_map>
#include <map>
#include <list>

#include "mem_allocator.h"

// 内存申请和释放

void MEM_base_libc()
{
    char* pcStart = (char*)malloc(1024);
    if (pcStart == NULL)
    {
        return;
    }

    strcpy(pcStart, "Hello libc");

    printf("%p: %s\n", pcStart, pcStart);

    free(pcStart);
}

void MEM_base_brk(int iSize)
{
    int iErr;
    void* apBreak[10];

    printf("current program break: %p\n", sbrk(0));
    for (int i = 0; i < 10; i++)
    {
        apBreak[i] = sbrk(iSize);
        printf("return value:          %p\n", apBreak[i]);
        printf("current program break: %p\n", sbrk(0));
    }

    printf("\n");
    // 释放内存
    for (int i = 10; i > 0; i--)
    {
        iErr = brk(apBreak[i-1]);
        printf("return value:          %d\n",iErr );
        if (iErr != 0)
        {
            printf("brk error, %s\n", strerror(errno));
        }
        printf("current program break: %p\n", sbrk(0));
    }
}

typedef struct tagMemBrkChunkNode
{

}MEM_BRK_CHUNK_NODE_S;

typedef struct tagMemBrkChunk
{
    void* pBreak;
    size_t ulSize;
    unsigned int uiRef; // 使用计数
    std::list<MEM_BRK_CHUNK_NODE_S> FreeList; // 空闲链表
}MEM_BRK_CHUNK_S;

typedef struct tagMemBrkNode
{
    void* pBreak;
    size_t ulSize;
}MEM_BRK_NODE_S;

typedef struct tagMemMMapNode
{
    void* pPtr;
    size_t ulSize;
}MEM_MMAP_NODE_S;



#define MEM_SIZE_USE_MMAP (1024 * 128)

std::unordered_map<void*, MEM_MMAP_NODE_S> g_mapMMap;

MEM_BRK_NODE_S g_astBrkNode[8];

#define MEM_BRK_SIZE (1024 * 132)

MEM_BRK_NODE_S* g_pstBrkNode = NULL;

typedef struct tagMemBrkInfo
{
    // 锁保护
    unsigned int uiMax;
    unsigned int uiUsed;
    std::map<void*, MEM_BRK_NODE_S> mapUsed;
}MEM_BRK_INFO_S;

MEM_BRK_INFO_S g_stBrkInfo = {};

void* alloc_brk(size_t size)
{
    unsigned int uiIndex = 0;

    if (g_stBrkInfo.uiMax == 0)
    {
        void* ptr = sbrk(MEM_BRK_SIZE);
        if (ptr == (void*)-1)
        {
            return NULL;
        }
    }
    
    void* ptr = sbrk(MEM_BRK_SIZE);
    if (ptr == (void*)-1)
    {
        return NULL;
    }

    MEM_BRK_NODE_S* pstBrkNode = (MEM_BRK_NODE_S*)ptr;
    pstBrkNode->pBreak = ptr;
    pstBrkNode->ulSize = MEM_BRK_SIZE;
}

void* alloc_mmap(size_t size)
{
    void* ptr = mmap(NULL, size, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0);
    if (ptr == MAP_FAILED)
    {
        return NULL;
    }

    printf("map size: %lu\n", g_mapMMap.size());

    g_mapMMap.insert({ptr, {ptr, size}});

    return ptr;
}

void* alloc_mem(size_t size)
{
    void* ptr = NULL;
    
    if (size == 0)
    {
        return ptr;
    }

    //size = ALIGN(size, 8);

    // 小内存申请使用 brk
    // 大内存申请使用 mmap
    if (size < MEM_SIZE_USE_MMAP)
    {
        ptr = alloc_brk(size);   
    }
    else
    {
        ptr = alloc_mmap(size);   
    }

    // 查找当前的内存区域中是否有空闲的内存

    // 没有则需要重新获取一块内存区域

    return ptr;
}

void free_mem(void* ptr)
{
    // 对应的内存地址是否是通过 mmap获取的
    auto it = g_mapMMap.find(ptr);
    if (it != g_mapMMap.end())
    {
        munmap(it->second.pPtr, it->second.ulSize);

        return;
    }

    auto itbrk = g_stBrkInfo.mapUsed.find(ptr);
    if (itbrk != g_stBrkInfo.mapUsed.end())
    {
        // 插入到空闲链表中

        // 获取 brk 区块
        
        // 如果区块使用为0，
    }
}


int main(int argc, char **argv)
{
    MemAllocator objAllocator;
    std::vector<void *> m_vecMem;


    objAllocator.ShowMemInfo();

    uint32_t uiTimes = 0;

    for (size_t ulSize = 8; ulSize <= MemAllocator::MEM_ALLOC_MAX_SIZE; ulSize <<= 1)
    {
        for (uint32_t uiTimes = 0; uiTimes < 3; uiTimes++)
        {
            void *pPtr = objAllocator.Alloc(ulSize);
            if (pPtr != nullptr)
            {
                //printf("size: %lu, ptr: %p\n", ulSize, pPtr);
                m_vecMem.push_back(pPtr);
            }
            else
            {
                printf("Error\n");
            }
        }
    }

    objAllocator.ShowMemInfo();

    // objAllocator.Alloc(8);
    // objAllocator.Alloc(8);
    // objAllocator.ShowMemInfo();

    // objAllocator.Alloc(16);
    // objAllocator.Alloc(16);
    // objAllocator.Alloc(16);
    // objAllocator.ShowMemInfo();

    return 0;
}